#pragma once
#if 0
#include <list>
#include <map>
#include <string>
#include "MessageRouter.h"

namespace OBS
{
	//add a data description for debugging
	struct MessageData
	{
		float ints[4];
		void * ptrs[4];
	};
}

typedef int (*CallbackFnPtr)(void * sender, std::string message, OBS::MessageData data);

/*

#define CALLBACK_TRIGGER_1(fn, event_name) \
	const std::string __trg_##fn[1] = {#event_name};\
	const int __trg_arg_count##fn = 1;

#define CALLBACK_TRIGGER_2(fn, event_name1, event_name2) \
	const std::string __trg_##fn[2] = {#event_name1, #event_name2};\
	const int __trg_arg_count##fn = 2;

#define CALLBACK_TRIGGER_3(fn, event_name1, event_name2, event_name3) \
	const std::string __trg_##fn[3] = {#event_name1,#event_name2,#event_name3};\
	const int __trg_arg_count##fn = 3;

//string_name_array, arg_count
#define CALLBACK_TRIGGERS(fn) __trg_##fn, __trg_arg_count##fn

#define OBS_TRIGGERS(fn) __trg_##fn
#define OBS_TRIGGER_COUNT(fn) __trg_arg_count##fn
*/


struct ObserverCollection
{
	void * _target;
	std::list<CallbackFnPtr> _fns;

	//this maps an event_string to a list of observers that are
	//fired when the event_string is emited
	std::map<std::string,std::list<CallbackFnPtr>> _mapping;
	
};

namespace OBS
{

	/*	NOTE: This observer will only be invoked by SPAM messages */
	inline void Register(ObserverCollection * oc, void * observee ,CallbackFnPtr fn_ptr)	{
		oc->_fns.push_back(fn_ptr);
		oc->_target = observee;
	}

	/*  NOTE: Use OBS_TRIGGERS(fn) and OBS_TRIGGER_COUNT(fn) to get the argurments*/
	inline void Register(ObserverCollection * oc, void * observee, 
		CallbackFnPtr fn_ptr, const std::string event_triggers[], const int trigger_count)
	{
		Register(oc, observee,fn_ptr);

		for (int i = 0; i < trigger_count ; i++)
		oc->_mapping[event_triggers[i]].push_back(fn_ptr);
	}

	/*
		SPAM: sends message to all connected observers,	otherwise only observers that are listening for specified msg will be invoked
		RECIPIENTS: the max amount of observers that can be invoked, 0 = unlimited
	*/
	inline std::list<int> EmitMultiple(ObserverCollection * oc, std::string msg, MessageData data, bool spam = false, int recipients = 0)
	{
		std::list<int> Result;
		int result_count = 0;

		std::list<CallbackFnPtr> observers;

		if (!spam)
		{
			observers = oc->_mapping[msg];
		}
		else
		{
			observers = oc->_fns;
		}

		std::list<CallbackFnPtr>::iterator callback_iter;
		for (callback_iter = observers.begin();
			callback_iter != observers.end(); 
			callback_iter++)
		{
			CallbackFnPtr callback_function = (*callback_iter);
			int current_result = callback_function(oc->_target,msg,data);
			Result.push_back(current_result);
			result_count++;

			if (recipients != 0)
			{
				if (result_count >= recipients)
				{
					return Result;
				}
			}
		}
		return Result;
	} 
}

/*
struct Alien
{
	ObserverCollection _oc;
	string _name;
};

CALLBACK_TRIGGER_1(CB_alien,ON_ALIEN_ARIVAL)
int CB_alien(void * sender, string message, int data)
{
	Alien * a = (Alien*)sender;
	cout <<"CB_alien "<<"name = " <<a->_name<< " " << message << " " << data <<endl;
	return 5;
}

int _example()
{ 
	Alien * a = new Alien();
	a->_name = "rick";

	OBS::Register(&a->_oc,(void *)a,CB_alien);

	OBS::EmitMultiple(&a->_oc, "BAR", -4, true);
}

*/



/*
TODO
	make typesafe
	make observer collection abstract <T>
	make results generic
	make interface
	separate from entity
	*/
#endif